#include "../include/socket.h"
#include "../include/global.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "../include/macro.h"
#include "../include/my_log.h"
#include <errno.h>
void _socket::init_epoll()
{
    this->epoll_fd=epoll_create(100); //这个size无所谓
    //创建监听套接字
    if(this->init_listening_socket()){
        printf("监听套接字创建逻辑走完\n");
    }else{
        //这都创建失败，那么直接不要了
        exit(1);
    }
    
    //初始化连接池
    if(this->init_connection_pool()){
        printf("连接池创建逻辑走完\n");
    }else{
        //这都创建失败，那么直接不要了
        exit(1);
    }
    
    //将监听套接字放入连接池子中
    this->add_listening_fd_to_connection_pool();    //如果失败会直接exit(1);

    
}

void _socket::start_this_pro()
{
    init_epoll();
    all_source_init();
    //开启线程池
    t_pool.create_pool(this->num_of_thread);
}

//这并不是异步关闭
void _socket::end_this_pro()
{
    my_log *log=my_log::get_log_instance();

    //1.关闭连接套接字--保证不会产生新连接
    for(auto it=listening_list.begin();it!=listening_list.end();++it){
        close((*it)->fd);   //关闭
        (*it)->fd=-1;
        (*it)->connection->fd=-1;   //表示结束
    }
    printf("优雅关闭服务器......关闭连接套接字--保证不会产生新连接\n");
    log->write_log(LOG_INFO,0,"优雅关闭服务器......关闭连接套接字--保证不会产生新连接");
    //2.清空当前客户端连接，先关闭读端，不要接收数据到线程池处理了，由于是单线程执行，走到这里，并没有去触发读数据---所以这一步可以跳过


    //3.关闭线程池，处理完当前的逻辑
    t_pool.end_all_thread();
    printf("优雅关闭服务器......处理完线程池任务并关闭线程池\n");
    log->write_log(LOG_INFO,0,"优雅关闭服务器......处理完线程池任务并关闭线程池 ");

    //4。处理当前逻辑，可能会有数据需要发送，那么去发送完，这个发送线程也得关闭掉
    this->send_message_thread_running_flag=PRO_END;
    pthread_cond_signal(&this->send_thread_cond);
    pthread_join(this->send_message_item->handler,NULL);
    printf("优雅关闭服务器......发送线程关闭成功\n");
    log->write_log(LOG_INFO,0,"优雅关闭服务器......发送线程关闭成功 ");
    
    // 5.还有踢人时钟线程，要不此时将客户端全部都踢出去，放到待释放连接队列里
    if(this->is_start_kick_map){
        this->kick_map_check_thread_running_flag=PRO_END;
        pthread_join(this->kick_map_item->handler,NULL);
        printf("优雅关闭服务器......踢人时钟线程关闭成功\n");
        log->write_log(LOG_INFO,0,"优雅关闭服务器......踢人时钟线程关闭成功");
    
    }

    //待释放连接队列里的就好了
    this->deal_recycle_running_flag=PRO_END;
    pthread_join(this->recycle_connection_item->handler,NULL);
    printf("优雅关闭服务器......待回收线程关闭成功\n");
    log->write_log(LOG_INFO,0,"优雅关闭服务器......待回收线程关闭成功");
    
    //此时所有的工作都已做完，一些单例类，会在程序完全结束后释放
    this->all_source_release();


}

void _socket::doing_epoll_wait()
{
    int num=epoll_wait(this->epoll_fd,this->events,MAX_EVENTS,-1);
    //这里也去检查返回错误码吧
    if(num==0){
        //由于是无线等待，那么按道理就不会返回这里
        my_log::get_log_instance()->write_log(LOG_INFO,0,"epoll_wait没有返回任何事件！！！");
        return;
    }
    if(num<0){
        if(errno==EINTR){
            //被信号打断
            return;
        }
        my_log::get_log_instance()->write_log(LOG_ERR,errno,"epoll_wait没有返回任何事件！！！");
        return;
    }
    for(int i=0;i<num;++i){
        //根据类型，处理掉数据
        connection_p con_p=(connection_p)events[i].data.ptr;
        if(events[i].events&EPOLLIN){
            (this->*(con_p->event_read_handler))(con_p);
        }

        if(events[i].events&EPOLLOUT){
            (this->*(con_p->event_write_handler))(con_p);
        }
    }
}